package com.example.util;

import lombok.Data;
import org.influxdb.InfluxDB;
import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.List;

/**
 * <p>
 * </p>
 *
 * @author:许腾飞
 * @since:2020/1/16 16:13
 */

@Data
@Component
public class InfluxDbUtils {
    Logger logger = LoggerFactory.getLogger(InfluxDbUtils.class);
    @Value("${spring.influx.user}")
    private String userName;
    @Value("${spring.influx.password}")
    private String password;
    @Value("${spring.influx.url}")
    private String url;
    @Value("${spring.influx.database}")
    public String database;
    //保留策略
    private String retentionPolicy;
    // InfluxDB实例
    private InfluxDB influxDB;

    // 数据保存策略  必須要先創建一个策略
    public static String PolicyNamePix = "logRetentionPolicy_";
    public static String DefaultPolicyName = "default";


    public InfluxDbUtils(String userName, String password, String url, String database,
                         String retentionPolicy) {
        this.userName = userName;
        this.password = password;
        this.url = url;
        this.database = database;
        this.retentionPolicy = retentionPolicy == null || "".equals(retentionPolicy) ? DefaultPolicyName : retentionPolicy;
        this.influxDB = influxDbBuild();
    }

    /**
     * 连接数据库 ，若不存在则创建
     *
     * @return influxDb实例
     */
    private InfluxDB influxDbBuild() {
        if (influxDB == null) {
            influxDB = InfluxDBFactory.connect(url, userName, password);
        }
        try {
            createDB(database);
            influxDB.setDatabase(database)
//            enableBatch这里第一个是point的个数，第二个是时间，单位毫秒，第三个时间单位一般设置成TimeUnit.MILLISECONDS就好，先不管。
//            point的个数和时间是联合使用的，如果满2000条或者10000毫秒，满足任何一个条件就会发送一次写的请求
              .enableBatch(2000,20000, TimeUnit.MILLISECONDS);

        } catch (Exception e) {
            logger.error("create influx db failed, error: {}", e.getMessage());
        } finally {
            createDefaultRetentionPolicy();//add by sixsix
            influxDB.setRetentionPolicy(retentionPolicy);
        }
        influxDB.setLogLevel(InfluxDB.LogLevel.BASIC);
        return influxDB;
    }

    /****
     *  创建数据库
     * @param database
     */
    private void createDB(String database) {
        influxDB.query(new Query("CREATE DATABASE " + database));
    }


    /**
     * 创建自定义保留策略
     *
     * @param policyName
     *            策略名
     * @param duration
     *            保存天数
     * @param replication
     *            保存副本数量
     * @param isDefault
     *            是否设为默认保留策略
     */
    public void createRetentionPolicy(String policyName, String duration, int replication, Boolean isDefault) {
        String sql = String.format("CREATE RETENTION POLICY \"%s\" ON \"%s\" DURATION %s REPLICATION %s ", policyName,
                database, duration, replication);
        if (isDefault) {
            sql = sql + " DEFAULT";
        }
        influxDB.query(new Query(sql));
    }


    /**
     * 创建默认的保留策略
     *
     * @param ：default，保存天数：30天，保存副本数量：1
     *            设为默认保留策略
     */
    public void createDefaultRetentionPolicy() {
        String command = String.format("CREATE RETENTION POLICY \"%s\" ON \"%s\" DURATION %s REPLICATION %s DEFAULT",
                DefaultPolicyName, database, "30d", 1);
        influxDB.query(new Query(command));
    }

    /**
     * 批量写入数据
     *
     * @param database
     *            数据库
     * @param retentionPolicy
     *            保存策略
     * @param consistency
     *            一致性
     * @param records
     *            要保存的数据（调用BatchPoints.lineProtocol()可得到一条record）
     */
    public void batchInsert(final String database, final String retentionPolicy, final InfluxDB.ConsistencyLevel consistency,
                            final List<String> records) {
        influxDB.write(database, retentionPolicy, consistency, records);
    }




}
